# 第9章 开发环境调优

# webpack开发效率插件

# webpack-dashboard

webpack-dashboard用来更好的展示打包信息。

npm i webpack-dashboard
1
const DashboardPlugin = require('webpack-dashboard/plgin');

module.exports = {
    plugins: [
        new DashboardPlugin();
    ]
}
1
2
3
4
5
6
7

还需要更改webpack的启动方式

// package.json
{
    "script": {
        "dev": "webpack-dashboard --webpack-dev-server"
    }
}
1
2
3
4
5
6

dashboard

# webpack-merge

const merge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
module.exports = merge.smart(commonConfig, {
    module: {
        rules: [
            {
                test: /\.css$/
            }
        ]
    }
})
1
2
3
4
5
6
7
8
9
10
11

在合并module.rules的过程中会以test作为标识符,当发现有相同项出现时会以后面的规则覆盖前面的规则。

# speed-measure-webpack-plugin

SMP可以分析出webpack整个打包过程中在各个loader和plugin上耗费的时间。

npm i speed-measure-webpack-plugin

// webpack.config.js
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
const smp = new SpeedMeasurePlugin();
module.exports = smp.wrap({
    entry: './app.js'
})
1
2
3
4
5
6
7
8

SpeedMeasurePlugin

# size-plugin

size-plugin帮助我们监控资源体积的变化。

npm i size-plugin

const SizePlugin = require('size-plugin');

module.exports = {
    plugins: [
        new SizePlugin()
    ]
}
1
2
3
4
5
6
7
8
9

每次打包后size-plugin都会输出本次构建的资源体积以及与上次构建相比体积变化了多少。

SizePlugin

# 模块热替换

最早调试代码都是改代码-刷新网页查看结果-再改代码。后来只要检测到代码改动就会自动重新构建,然后触发网页刷新。webpack在这个基础上又进一步,可以让代码在网页不刷新的前提下得到最新的改动,这就是模块热替换功能(Hot Module Replacement, HMR)。

# 开启HMR

webpack本身的命令行不支持HMR,项目要保证是基于webpack-dev-server或者webpack-dev-middle进行开发的。

const webpack = require('webpack');
module.exports = {
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ],
    devServer: {
        hot: true
    }
}
1
2
3
4
5
6
7
8
9

上面配置webpack会为每个模块绑定一个module.hot对象。这个对象包含了HMR的API。

调用HMR API有两种方式,一种是手动添加这部分代码;另一种是借助工具如react-hot-loader、vue-loader等。

// index.js
import {add} from 'util.js';
add(2, 3);

if(module.hot) {
    module.hot.accept();
}
1
2
3
4
5
6
7

当现有模块发生变动时,HMR会使应用在当前浏览器环境下重新执行一遍index.js(包括依赖)的内容,但是页面本身不会刷新。

# HMR原理

在开启HMR的状态下进行开发,资源的体积会比原来的大很多,因为webpack为了实现HMR而注入了很多相关代码。

在本地开发环境下,浏览器是客户端,webpack-dev-server(WDS)相当于是我们的服务端。HMR的核心就是客户端从服务端拉取更新后的资源。

WDS与浏览器间维护了一个websocket,当本地资源发生变化时WDS会向浏览器推送更新时间,并带上这次构建的hash,让客户端与上次资产进行比对。通过hash的对比可以防止冗余更新的出现。因为很多时候源文件的更改并不一定代码构建结果的更改(比如添加了一个文件末尾空行)。

现在客户端已经知道新的构建结果和当前的有了差别,就会向WDS发起一个请求来获取更改文件的列表。通常这个请求的名字为[hash].hot-update.json。

// WDS向浏览器的返回值
{"h": "e388ddsjdfas", "c":{"main": true}}
1
2

需要更新的chunk为main,版本为e388ddsjdfas。这样客户端就可以再借助这些信息继续向WDS获取该chunk的增量更新。

// 增量接口
http://localhot:3000/dist/main.2410644c20694722f9ca.hot-update.js

// 返回值
webpackHotUpdate("main", {
    (function(module, __webpack_exports__, __webpack_require__){
        "use strict";
        eval(...)
    })
})
1
2
3
4
5
6
7
8
9
10
// index.js
if(module.hot) {
    module.hot.decline();
    module.hot.accept(['./util.js']);
}
1
2
3
4
5

module.hot.decline是将当前index.js的HMR关闭掉,后面一句是当util.js改变时依然可以启用HMR更新。